package com.xyw.code.springcloudsecurityoath2.config;

import com.xyw.code.springcloudsecurityoath2.constant.Authorities;
import com.xyw.code.springcloudsecurityoath2.constant.CustomAuthenticationEntryPoint;
import com.xyw.code.springcloudsecurityoath2.constant.CustomLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;

@Configuration
public class OAuth2Configuration {
    @Configuration
    @EnableResourceServer
    @Order(1)
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Autowired
        private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

        @Autowired
        private CustomLogoutSuccessHandler customLogoutSuccessHandler;

        @Override
        public void configure(HttpSecurity http) throws Exception {

            http
                    .exceptionHandling()
                    .authenticationEntryPoint(customAuthenticationEntryPoint)
                    .and()
                    .logout()
                    .logoutUrl("/oauth/logout")
                    .logoutSuccessHandler(customLogoutSuccessHandler)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/hello/").permitAll()
                    .antMatchers("/secure/**").authenticated();

        }

    }

    @Configuration
    @EnableAuthorizationServer
    @ConfigurationProperties(prefix = "authentication.oauth", ignoreUnknownFields = true)
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {

        private static String PROP_CLIENTID = "";
        private static String PROP_SECRET = "";
        private static Integer PROP_TOKEN_VALIDITY_SECONDS ;


        @Autowired
        private DataSource dataSource;

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {
            endpoints
                    .tokenStore(tokenStore())
                    .authenticationManager(authenticationManager);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients
                    .inMemory()
                    .withClient(PROP_CLIENTID)
                    .scopes("read", "write")
                    .authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
                    .authorizedGrantTypes("password", "refresh_token")
                    .secret(PROP_SECRET)
                    .accessTokenValiditySeconds(PROP_TOKEN_VALIDITY_SECONDS);
        }

        @Override
        public void setEnvironment(Environment environment) {
            this.PROP_CLIENTID = environment.getProperty("authentication.oauth.clientid");
            this.PROP_SECRET = environment.getProperty("authentication.oauth.secret");
            this.PROP_TOKEN_VALIDITY_SECONDS = environment.getProperty("authentication.oauth.tokenValidityInSeconds")==null?1800:new Integer(environment.getProperty("authentication.oauth.tokenValidityInSeconds"));
            System.out.println(this.PROP_CLIENTID);
            System.out.println(this.PROP_SECRET);
            System.out.println(this.PROP_TOKEN_VALIDITY_SECONDS);

        }
    }
}
